import { effect } from "./effect.js";
import { isReactive } from "./reactive.js";
import { isRef } from "./ref.js";
import { isComputed } from "./computed.js";
import { isFunction } from "./utils.js";

export function isReactiveData(data) {
  return isRef(data) || isReactive(data) || isComputed(data);
}

function createWatcher(source, cb, options, isWatchEffect = false) {
  let newValues = [];
  let oldValues = [];
  let index;

  function __watcher(source, cb, options, newValues, oldValues, index) {
    const { immediate = false, deep = false } = options;
    let run;
    // 手动建立依赖关系
    if (isFunction(source)) {
      run = source;
    }

    if (isReactiveData(source)) {
      if (isReactive(source)) {
        run = () => {
          const keys = Object.keys(source);
          console.log("keys", keys);
          keys.forEach((key) => {
            console.log("key", key);
            source[key];
            if (deep) {
              __watcher(source[key], cb, { deep });
            }
          });
        };
      } else {
        run = () => {
          source.value;
          if (deep) {
            __watcher(source.value, cb, { deep });
          }
        };
      }
    }

    if (Array.isArray(source)) {
      run = () => {
        source.forEach((item, index) => {
          newValues[index] = oldValues[index] = isFunction(item)
            ? item()
            : item;
          __watcher(item, cb, { deep }, newValues, oldValues, index);
        });
      };
      run();
    }

    if (run) {
      effect(run, {
        lazy: true,
        scheduler: ({ effectFn, newValue, oldValue }) => {
          console.log("scheduler");
          if (isWatchEffect) {
            effectFn();
            return;
          }
          if (newValues.length === 0) {
            cb && cb(newValue, oldValue);
            return;
          }
          newValues[index] = newValue;
          oldValues[index] = oldValue;
          cb && cb(newValues, oldValues);
        },
      })();
    }
  }

  __watcher(source, cb, options, newValues, oldValues, index);
}

function watch(source, cb, options = {}) {
  createWatcher(source, cb, options);
}

export default watch;

export function watchEffect(fn, options = {}) {
  createWatcher(fn, null, options, true);
}
